package ni;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.ArrayList;

import signals.*;

/**
 * UDPSender is really useful to send signals over the network
 *
 * @author gb
 */
public class UDPSender {

    private DatagramSocket senderSocket;

    /**
     * Creates a UDPSender object
     *
     * @param senderSocket the socket the UDPSender is going to use to send the
     * signals
     */
    public UDPSender(DatagramSocket senderSocket) {
        super();
        //Creates a sender socket that'll stay open until release
        this.senderSocket = senderSocket;
    }

    /**
     * Sends a Hello Signal over the network to the broadcastIP from netName
     *
     * @param concatName is the netName of the local user (ex :
     * gabriel@192.168.1.2)
     * @param broadcastIp is the broadcast IP of the network
     * @throws SignalTooBigException when a signal is bigger than
     * Signals.MAX_SIZE bytes this exception is thrown
     * @throws IOException when datagram could not be sent
     */
    public void sendHello(String concatName, InetAddress broadcastIp) throws SignalTooBigException, IOException {
        Hello hello = new Hello(concatName);
        ChatNI.printDebug("UDPSender", "sendHello", "Sending from " + concatName);
        ChatNI.printDebug("UDPSender", "sendHello", "Sending to " + broadcastIp);

        sendSignal(hello, broadcastIp);
    }

    /**
     * Sends a Goodbye Signal over the network to the broadcastIP from netName
     *
     * @param concatName is the netName of the local user (ex :
     * gabriel@192.168.1.2)
     * @param broadcastIp is the broadcast IP of the network
     * @throws SignalTooBigException when a signal is bigger than
     * Signals.MAX_SIZE bytes this exception is thrown
     * @throws IOException when datagram could not be sent
     */
    public void sendGoodbye(String concatName, InetAddress broadcastIp) throws SignalTooBigException, IOException {
        Goodbye goodbye = new Goodbye(concatName);

        ChatNI.printDebug("UDPSender", "sendGoodbye", "Sending from " + concatName);

        sendSignal(goodbye, broadcastIp);
    }

    /**
     * Sends a HelloOK Signal over the network to the remote user, from netName
     *
     * @param concatName is the netName of the local user (ex :
     * gabriel@192.168.1.2)
     * @param remoteUsername is the remote user we want to send the signal to,
     * netName (ex : remote@192.168.1.3)
     * @throws SignalTooBigException when a signal is bigger than
     * Signals.MAX_SIZE bytes this exception is thrown
     * @throws IOException when datagram could not be sent
     */
    public void sendHelloOK(String concatName, String remoteUsername) throws SignalTooBigException, IOException {
        ChatNI.printDebug("UDPSender", "sendHelloOK", "Sending from " + concatName + "to" + remoteUsername);

        HelloOK helloOK = new HelloOK(concatName);
        sendSignal(helloOK, ChatNI.extractIpFromUsername(remoteUsername));

    }

    /**
     * Sends a TextMessage Signal over the network to the selected remote users
     * from netName
     *
     * @param message the message to send
     * @param concatName is the netName of the local user (ex :
     * gabriel@192.168.1.2)
     * @param to the list of user to whom the message is destined
     * @throws SignalTooBigException when a signal is bigger than
     * Signals.MAX_SIZE bytes this exception is thrown
     * @throws IOException when datagram could not be sent
     */
    public void sendTextMessage(String message, String concatName, ArrayList<String> to) throws SignalTooBigException, IOException {
        TextMessage mes = new TextMessage(message, concatName, to);
        for (String dest : to) {
            ChatNI.printDebug("UDPSender", "sendTextMessage", "Sending from " + concatName + " to " + dest);
            sendSignal(mes, ChatNI.extractIpFromUsername(dest));
        }
    }

    /**
     * Sends a File Proposal Signal over the network the selected remote users
     * from the netName
     *
     * @param fileName the name of the file that local user proposes
     * @param size the size of this file
     * @param from the local netName (ex : gabriel@192.168.1.2)
     * @param to the list of persons to whom the proposal is destined
     * @throws SignalTooBigException when a signal is bigger than
     * Signals.MAX_SIZE bytes this exception is thrown
     * @throws IOException when datagram could not be sent
     */
    public void sendFileProposal(String fileName, long size, String from, ArrayList<String> to) throws SignalTooBigException, IOException {
        FileProposal fp = new FileProposal(fileName, size, from, to);
        for (String dest : to) {
            ChatNI.printDebug("UDPSender", "sendFileProposal", "Sending from " + from + " to " + dest + ".");
            sendSignal(fp, ChatNI.extractIpFromUsername(dest));
        }
    }

    /**
     * Sends a File Proposal Accepted Signal over the network the remote user
     * from the netName
     *
     * @param fileName the name of the file that local user accepts to receive
     * @param netName the local netName (ex : gabriel@192.168.1.2)
     * @param to the remote user netName from who accepted the file
     * @throws SignalTooBigException when a signal is bigger than
     * Signals.MAX_SIZE bytes this exception is thrown
     * @throws IOException when datagram could not be sent
     */
    public void sendFileTransferAccepted(String fileName, String netName, String to) throws SignalTooBigException, IOException {
        Signal fta = new FileTransferAccepted(fileName, netName);
        ChatNI.printDebug("UDPSender", "sendFileTransferAccepted", "Sending from " + netName + " to " + to + " only.");
        sendSignal(fta, ChatNI.extractIpFromUsername(to));
    }

    /**
     * Sends a File Proposal Not Accepted Signal over the network the remote
     * user from the netName
     *
     * @param fileName the name of the file that local user does not accept to
     * receive
     * @param netName the local netName (ex : gabriel@192.168.1.2)
     * @param to the remote user netName from who the local user did not accept
     * the file
     * @throws SignalTooBigException when a signal is bigger than
     * Signals.MAX_SIZE bytes this exception is thrown
     * @throws IOException when datagram could not be sent
     */
    public void sendFileTransferNotAccepted(String fileName, String netName, String to) throws SignalTooBigException, IOException {
        Signal ftna = new FileTransferNotAccepted(fileName, netName);
        ChatNI.printDebug("UDPSender", "sendFileTransferNotAccepted", "Sending from " + netName + " to " + to + " only.");
        sendSignal(ftna, ChatNI.extractIpFromUsername(to));
    }

    /**
     * Sends a signal over the network to a particular IP (could be broadcast)
     *
     * @param signal the Signal to send
     * @param destIp the destination IP address where the signal should be sent
     * @throws SignalTooBigException
     * @throws IOException
     */
    private void sendSignal(Signal signal, InetAddress destIp) throws SignalTooBigException, IOException {

        ChatNI.printDebug("UDPSender", "sendSignal", "Sending a signal to " + destIp);

        byte[] sendData = Signal.toByteArray(signal);

        DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, destIp, ChatNI.receivePort);
        this.senderSocket.send(sendPacket);

    }
}
